package org.grow.loginto.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import org.grow.loginto.dao.UserInfoService;
import org.grow.loginto.entity.UserInfo;
import org.grow.loginto.security.ColdVoter;
import org.grow.loginto.security.Hot;
import org.grow.loginto.security.HotLoginHandler;
import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.vote.AffirmativeBased;

import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;


/**
 * @Author: xwg
 * @CreateDate: 21-6-2
 */
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private HotLoginHandler hotLoginHandler;
    @Autowired
    private Hot hot;
    @Autowired
    private ColdVoter coldVoter;
//    @Autowired
//    private AccessDecisionVoter accessDecisionVoter;
//    @Autowired
//    private AccessDecisionManager accessDecisionManager;
//    @Autowired
//    private FilterSecurityInterceptor filterSecurityInterceptor;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .successHandler(hotLoginHandler)
                .failureHandler(hotLoginHandler)
                .permitAll();
//        http.formLogin().disable();

        http.logout()
                .logoutUrl("/logout")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        Object principal = authentication.getPrincipal();
                        if (principal == null) {
                            httpServletResponse.setStatus(777);
                            httpServletResponse.getWriter().println("用户本来就不存在，登出为何？");
                            httpServletResponse.flushBuffer();

                            return;
                        }
                        System.out.println(authentication.getPrincipal() + " 将要登出");

                        httpServletResponse.setStatus(200);

                        httpServletResponse.getWriter().println("good bye");
                        httpServletResponse.flushBuffer();

                    }
                });


        http.csrf().disable();
        http.cors().disable();
        http.httpBasic().disable();

//        http.addFilterBefore(,FilterSecurityInterceptor.class);

        UserInfo anonymousInfo = new UserInfo();
        anonymousInfo.setNickname("匿名者");
        anonymousInfo.setPassword("121212");
        anonymousInfo.setLastLoginTime(LocalDateTime.parse("2020-02-02T12:22:32"));
        anonymousInfo.setUsername("anonymous_user");
        anonymousInfo.setUserId(10000);
        http.anonymous().principal(anonymousInfo);
//        http.addFilterBefore(filterSecurityInterceptor,
//                FilterSecurityInterceptor.class);
        http.authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setSecurityMetadataSource(hot);
                        o.setAccessDecisionManager(new AffirmativeBased(
                                Arrays.asList(coldVoter)
                        ));
                        return o;
                    }
                })

//                .antMatchers("/reg/*").permitAll()
                .anyRequest().authenticated();

//                .anyRequest().authenticated();
//        http.authorizeRequests().anyRequest().permitAll();
//        http.
//        http.authorizeRequests().withObjectPostProcessor(objectPostProcessor);
        http.exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {

                        httpServletResponse.setStatus(990);

                        httpServletResponse.getWriter().println(objectMapper.writeValueAsString("没有身份信息，连匿名都不是 " + e.getMessage()));
                        httpServletResponse.flushBuffer();
                    }
                })
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
//                        AccessDeniedHandlerImpl
                        httpServletResponse.setStatus(930);
                        String requestURI = httpServletRequest.getRequestURI();
                        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                        UserDetails principal = (UserDetails) authentication.getPrincipal();
                        httpServletResponse.getWriter().println(objectMapper.writeValueAsString("虽然有身份信息，但是" + principal.getUsername() + "没有这个权限访问　" + requestURI + "  ==  " + e.getMessage()));
                        httpServletResponse.flushBuffer();
                    }
                });
    }

    @Autowired
    private UserInfoService userInfoService;


    @Override
    protected UserDetailsService userDetailsService() {
        return userInfoService;
    }

/*
    @Override
    public void configure(WebSecurity web) throws Exception {
        //放行所有请求,不进入11链中,不进行认证和权限
        //注意对比权限验证在fsi放行,此处根本不进行身份认证,所以未登录状态可以访问的在此设置
        //匿名用户与未登录用户异同,都是后台无session,问题在于匿名用户可以是session过期问题导致的
        web.ignoring().antMatchers("/swagger-ui.html");


    }*/


}
